// generate control signals for instruction queue
module instr_queue_wrap(
  input clk,
  input rst,

  input de_stall,
  input de_flush,

  input  valid_i,
  output stall_o,

  input [ 31:0] pc_i,
  input [127:0] instr_i,
  input [  3:0] rstrb_i,
  input         br_pre_taken_i,
  input [31:0]  br_pre_pc_i,
  input [1:0] br_offset_i,
  input         ft_tlbre_i,
  input         ft_tlbi_i,
  input         ft_adel_i,

  output [31:0] pc_o,
  output [31:0] instr_o,
  output        br_pre_taken_o,
  output [31:0] br_pre_pc_o,
  output        valid_o,
  output        valid_next_o,
  output        ft_tlbre_o,
  output        ft_tlbi_o,
  output        ft_adel_o
);

  wire [399:0] iq_wdata;
  wire iq_wvalid;
  wire iq_wready;
  wire [2:0] iq_wnum;

  wire [1:0] iq_rvalid;
  wire [1:0] iq_rready;
  wire [99:0] iq_rdata;
  wire [31:0] iq_rpc [1:0];
  wire [31:0] iq_rinstr [1:0];
  wire iq_rbr_pre_taken [1:0];
  wire [31:0] iq_rbr_pre_pc [1:0];
  wire iq_rft_tlbre [1:0];
  wire iq_rft_tlbi [1:0];
  wire iq_rft_adel [1:0];
  
  wire [31:0] pc_vec [3:0];
  wire [31:0] instr_vec [3:0];
  wire        br_pre_taken_vec [3:0];
  wire [99:0] wdata_packed [3:0];

  genvar j;
  generate
    for (j = 0; j < 4; j = j + 1) begin
      assign pc_vec[j] = pc_i + j * 4;
      assign instr_vec[j]  = instr_i[j * 32 + 31 : j * 32];
      assign br_pre_taken_vec[j] = (pc_vec[j][3:2] == br_offset_i) ? br_pre_taken_i : 1'b0;
      assign wdata_packed[j] = {
        pc_vec[j],
        instr_vec[j],
        br_pre_taken_vec[j],
        br_pre_pc_i,
        ft_tlbre_i,
        ft_tlbi_i,
        ft_adel_i
      };
    end
  endgenerate

  assign iq_wdata = {
    wdata_packed[3],
    wdata_packed[2],
    wdata_packed[1],
    wdata_packed[0]
  };
  assign iq_wvalid = valid_i;
  assign stall_o = !iq_wready;
  assign iq_wnum = 
    {3{rstrb_i == 4'b1111}} & (br_offset_i + 1) |
    {3{rstrb_i == 4'b0111}} & (br_offset_i    ) |
    {3{rstrb_i == 4'b0011}} & (br_offset_i - 1) |
    {3{rstrb_i == 4'b0001}} & (br_offset_i - 2) ;

  // TODO: for single issue, iq_rready[1] is unvalid (1'b0)
  assign iq_rready = {1'b0, !de_stall};
  assign valid_o = iq_rvalid[0];
  assign valid_next_o = iq_rvalid[1];
  assign {
    iq_rpc[1],
    iq_rinstr[1],
    iq_rbr_pre_taken[1],
    iq_rbr_pre_pc[1],
    iq_rft_tlbre[1],
    iq_rft_tlbi[1],
    iq_rft_adel[1],
    iq_rpc[0],
    iq_rinstr[0],
    iq_rbr_pre_taken[0],
    iq_rbr_pre_pc[0],
    iq_rft_tlbre[0],
    iq_rft_tlbi[0],
    iq_rft_adel[0]
  } = iq_rdata;

  assign pc_o = iq_rpc[0];
  assign instr_o = iq_rinstr[0];
  assign br_pre_taken_o = iq_rbr_pre_taken[0];
  assign br_pre_pc_o = iq_rbr_pre_pc[0];
  assign ft_tlbre_o = iq_rft_tlbre[0];
  assign ft_tlbi_o = iq_rft_tlbi[0];
  assign ft_adel_o = iq_rft_adel[0];

  instr_queue #(
    .DEPTH(4),
    .WIDTH(100),
    .WAY(4)
  ) mycpu_instr_queue (
    .clk(clk),
    .rst(rst),
    .flush(de_flush),

    .wvalid(iq_wvalid),
    .wready(iq_wready),
    .wnum(iq_wnum),
    .wdata(iq_wdata),

    .rvalid(iq_rvalid),
    .rready(iq_rready),
    .rdata(iq_rdata)
  );

endmodule
